package github.kawaiior.yuanchuxiuzhen.util;

import net.minecraft.entity.Entity;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.potion.Effect;
import net.minecraft.potion.EffectInstance;
import net.minecraft.util.math.*;
import net.minecraft.util.math.vector.Vector3d;
import net.minecraft.world.World;

import javax.annotation.Nullable;
import java.util.List;
import java.util.Optional;

public class EntityUtil {

    /**
     * What, if anything, is the player currently looking at?
     */
    @Nullable
    public static Entity getPlayerLookTarget(World world, LivingEntity living, double range) {
        Entity pointedEntity = null;
        Vector3d srcVec = new Vector3d(living.getPosX(), living.getPosY() + living.getEyeHeight(), living.getPosZ());
        Vector3d lookVec = living.getLook(1.0F);
        Vector3d destVec = srcVec.add(lookVec.x * range, lookVec.y * range, lookVec.z * range);
        float var9 = 1.0F;
        List<Entity> possibleList = world.getEntitiesWithinAABBExcludingEntity(living, living.getBoundingBox().expand(lookVec.x * range, lookVec.y * range, lookVec.z * range).grow(var9, var9, var9));
        double hitDist = 0;

        for (Entity possibleEntity : possibleList) {

            if (possibleEntity.canBeCollidedWith()) {
                float borderSize = possibleEntity.getCollisionBorderSize();
                AxisAlignedBB collisionBB = possibleEntity.getBoundingBox().grow(borderSize, borderSize, borderSize);
                Optional<Vector3d> interceptPos = collisionBB.rayTrace(srcVec, destVec);

                if (collisionBB.contains(srcVec)) {
                    if (0.0D < hitDist || hitDist == 0.0D) {
                        pointedEntity = possibleEntity;
                        hitDist = 0.0D;
                    }
                } else if (interceptPos.isPresent()) {
                    double possibleDist = srcVec.distanceTo(interceptPos.get());

                    if (possibleDist < hitDist || hitDist == 0.0D) {
                        pointedEntity = possibleEntity;
                        hitDist = possibleDist;
                    }
                }
            }
        }
        return pointedEntity;
    }

    public static BlockPos getPlayerLookBlockPos(LivingEntity living, double maxRange) {
        World world = living.getEntityWorld();
        Vector3d start = living.getEyePosition(1.0F);
        Vector3d lookVec = living.getLookVec();
        Vector3d end = start.add(lookVec.scale(maxRange));

        BlockRayTraceResult rayTraceResult = world.rayTraceBlocks(new RayTraceContext(start, end, RayTraceContext.BlockMode.OUTLINE, RayTraceContext.FluidMode.NONE, living));

        if (rayTraceResult.getType() == RayTraceResult.Type.BLOCK) {
            return rayTraceResult.getPos();
        }

        return new BlockPos(end);
    }

    /**
     * 给玩家添加药水效果
     * 如果已存在相同的药水效果，那么增加药水效果的时间
     */
    public static void addEffect(PlayerEntity player, Effect effect, int seconds){
        EffectInstance instance = player.getActivePotionEffect(effect);
        if (instance==null){
            player.addPotionEffect(new EffectInstance(effect, seconds*20));
            return;
        }
        int duration = instance.getDuration();
        int amplifier = instance.getAmplifier();
        player.addPotionEffect(new EffectInstance(effect, duration+seconds*20, amplifier));
    }

    /**
     * 给target实体添加动量 相对于某个living entity
     */
    public static void playerMotionEntity(LivingEntity target, LivingEntity attacker,
                                          double xForce, double yForce, double zForce,
                                          double xIncrease, double yIncrease, double zIncrease){
        double dx = target.getPosX() - attacker.getPosX();
        double dy = target.getPosY() - attacker.getPosY();
        double dz = target.getPosZ() - attacker.getPosZ();

        double distance = Math.sqrt(dx * dx + dy * dy + dz * dz);
        dx /= distance;
        dy /= distance;
        dz /= distance;

        target.setMotion((dx+xIncrease) * xForce, (dy+yIncrease) * yForce, (dz+zIncrease) * zForce);
    }

    public static void playerMotionEntity(LivingEntity target, LivingEntity attacker,
                                          double xForce, double yForce, double zForce){
        playerMotionEntity(target, attacker, xForce, yForce, zForce, 0, 0, 0);
    }

}
